//
//  MLNavigationController.m
//  MultiLayerNavigation
//
//  Created by Feather Chan on 13-4-12.
//  Copyright (c) 2013年 Feather Chan. All rights reserved.
//

#define KEY_WINDOW  [[UIApplication sharedApplication]keyWindow]

#import "MLNavigationController.h"
#import <QuartzCore/QuartzCore.h>

static const CGFloat KZposition = -4000;
static const CGFloat kViewScaling = 0.95;

@interface MLNavigationController () <UIGestureRecognizerDelegate> {
    CGPoint startTouch;
    UIImageView *lastScreenShotView;
    UIView *blackMask;
}

@property (nonatomic,retain) UIView *backgroundView;
@property (nonatomic, retain) NSMutableArray *screenShotsList;
@property (nonatomic, assign) BOOL isMoving;
@property (nonatomic, retain) UIImageView *presentBackgroundView;
@end

@implementation MLNavigationController

@synthesize canDragBackInMainView = _canDragBackInMainView;

- (instancetype)initWithNavigationBarClass:(__unsafe_unretained Class)navigationBarClass toolbarClass:(__unsafe_unretained Class)toolbarClass rootViewController:(UIViewController *)rootViewController{
    self = [self initWithNavigationBarClass:navigationBarClass toolbarClass:toolbarClass];
    if (self) {
        self.viewControllers = @[rootViewController];
    }
    return self;
}

- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil {
    self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
    if (self) {
        self.screenShotsList = [[NSMutableArray alloc]initWithCapacity:2];
        self.canDragBack = YES;
        self.canDragBackInMainView = YES;
    }
    return self;
}

- (void)viewDidLoad {
    [super viewDidLoad];
    UIImageView *shadowImageView = [[UIImageView alloc]initWithImage:[UIImage imageNamed:@"leftside_shadow_bg"]];
    shadowImageView.frame = CGRectMake(-10, 0, 10, self.view.frame.size.height);
    [self.view addSubview:shadowImageView];
}

- (void)presentViewController:(UIViewController *)viewControllerToPresent animated:(BOOL)flag completion:(void (^)(void))completion {
    if (!flag) {
        [super presentViewController:viewControllerToPresent animated:flag completion:completion];
        return;
    }
    
    [self moveEndWithAnimated:NO];
    
    self.presentBackgroundView = [[UIImageView alloc] initWithImage:[self capture]];
    [self.view.superview addSubview:self.presentBackgroundView];
    
    self.view.hidden = YES;
    
    UIView *primaryView = self.presentBackgroundView;
    
    void (^modifyAngle) (void) = ^{
        CALayer *layer = primaryView.layer;
        layer.zPosition = KZposition;
        CATransform3D rotationAndPerspectiveTransform = layer.transform;
        rotationAndPerspectiveTransform.m34 = 1.0 / -300;
        layer.transform = CATransform3DRotate(rotationAndPerspectiveTransform,
                                              2.0f * M_PI / 180.0f,
                                              1.0f,
                                              0.0f,
                                              0.0f);
    };
    void (^scaleView) (void) = ^{
        CGAffineTransform xForm = primaryView.transform;
        primaryView.transform = CGAffineTransformScale(xForm, kViewScaling, kViewScaling);
    };
    
    [UIView animateWithDuration:0.3
                     animations:modifyAngle
                     completion:^(BOOL finished) {
                         if (finished) {
                             [UIView animateWithDuration:0.3
                                                   delay:0.0
                                                 options:UIViewAnimationOptionCurveEaseIn
                                              animations:scaleView
                                              completion:NULL];
                             void (^modalBlock) (void);
                             
                             modalBlock = ^{
                                 [super presentViewController:viewControllerToPresent animated:YES completion:^{
                                     
                                 }];
                             };
                             
                             dispatch_time_t modalDelay =
                             dispatch_time(DISPATCH_TIME_NOW, 1000000);
                             dispatch_after(modalDelay, dispatch_get_main_queue(), modalBlock);
                             
                         }
                     }];
}

- (void)presentModalViewController:(UIViewController *)modalViewController animated:(BOOL)animated {
    if (!animated) {
        [super presentModalViewController:modalViewController animated:animated];
        return;
    }
    
    [self moveEndWithAnimated:NO];
    self.presentBackgroundView = [[UIImageView alloc] initWithImage:[self capture]];
    [self.view.superview addSubview:self.presentBackgroundView];
    self.view.hidden = YES;
    UIView *primaryView = self.presentBackgroundView;
    
    void (^modifyAngle) (void) = ^{
        CALayer *layer = primaryView.layer;
        layer.zPosition = KZposition;
        CATransform3D rotationAndPerspectiveTransform = layer.transform;
        rotationAndPerspectiveTransform.m34 = 1.0 / -300;
        layer.transform = CATransform3DRotate(rotationAndPerspectiveTransform,
                                              2.0f * M_PI / 180.0f,
                                              1.0f,
                                              0.0f,
                                              0.0f);
    };
    void (^scaleView) (void) = ^{
        CGAffineTransform xForm = primaryView.transform;

        primaryView.transform = CGAffineTransformScale(xForm, kViewScaling, kViewScaling);
    };
    
    [UIView animateWithDuration:0.3
                     animations:modifyAngle
                     completion:^(BOOL finished) {
                         if (finished) {
                             [UIView animateWithDuration:0.3
                                                   delay:0.0
                                                 options:UIViewAnimationOptionCurveEaseIn
                                              animations:scaleView
                                              completion:NULL];
                             void (^modalBlock) (void);
                             
                                 modalBlock = ^{
                                     [super presentViewController:modalViewController animated:YES completion:^{
                                         
                                     }];
                                 };
                             
                             dispatch_time_t modalDelay =
                             dispatch_time(DISPATCH_TIME_NOW, 1000000);
                             dispatch_after(modalDelay, dispatch_get_main_queue(), modalBlock);
                             
                         }
                     }];
}

- (void)dismissViewControllerAnimated:(BOOL)flag completion:(void (^)(void))completion {
    [super dismissViewControllerAnimated:flag completion:completion];
    UIView *primaryView = self.presentBackgroundView;
    void (^modifyAngle) (void) = ^{
        CALayer *layer = primaryView.layer;
        layer.zPosition = KZposition;
        CATransform3D rotationAndPerspectiveTransform = layer.transform;
        rotationAndPerspectiveTransform.m34 = 1.0 / 300;
        layer.transform = CATransform3DRotate(rotationAndPerspectiveTransform,
                                              -3.0f * M_PI / 180.0f,
                                              1.0f,
                                              0.0f,
                                              0.0f);
        
    };
    
    void (^scaleView) (void) = ^{
        primaryView.transform =  CGAffineTransformScale(primaryView.transform, 1.0, 1.0);
    };
    
    void (^animationBlock) (void) = ^{
        [UIView animateWithDuration:0.3
                              delay:0.05
                            options:UIViewAnimationOptionCurveEaseIn
                         animations:modifyAngle
                         completion:^(BOOL finished) {
                             [UIView animateWithDuration:0.3
                                              animations:scaleView
                                              completion:^(BOOL finished) {
                                                  if (finished) {
                                                      [self.presentBackgroundView removeFromSuperview];
                                                      self.presentBackgroundView = nil;
                                                      self.view.hidden = NO;
                                                  }
                                              }];
                         }];
        
    };
    
    [super dismissViewControllerAnimated:flag completion:^{
        CALayer *layer = primaryView.layer;
        layer.zPosition = 0;
    }];
    
    primaryView.transform =  CGAffineTransformScale(primaryView.transform, kViewScaling, kViewScaling);
    
    dispatch_time_t modalDelay =
    dispatch_time(DISPATCH_TIME_NOW, 20000000);
    dispatch_after(modalDelay, dispatch_get_main_queue(), animationBlock);
}

- (void)dismissModalViewControllerAnimated:(BOOL)animated {
    UIView *primaryView = self.presentBackgroundView;
    void (^modifyAngle) (void) = ^{
        CALayer *layer = primaryView.layer;
        layer.zPosition = KZposition;
        CATransform3D rotationAndPerspectiveTransform = layer.transform;
        rotationAndPerspectiveTransform.m34 = 1.0 / 300;
        layer.transform = CATransform3DRotate(rotationAndPerspectiveTransform,
                                              -3.0f * M_PI / 180.0f,
                                              1.0f,
                                              0.0f,
                                              0.0f);
        
    };
    
    void (^scaleView) (void) = ^{
        primaryView.transform =  CGAffineTransformScale(primaryView.transform, 1.0, 1.0);
    };
    
    void (^animationBlock) (void) = ^{
        [UIView animateWithDuration:0.3
                              delay:0.05
                            options:UIViewAnimationOptionCurveEaseIn
                         animations:modifyAngle
                         completion:^(BOOL finished) {
                             [UIView animateWithDuration:0.3
                                              animations:scaleView
                                              completion:^(BOOL finished) {
                                                  if (finished) {
                                                      [self.presentBackgroundView removeFromSuperview];
                                                      self.presentBackgroundView = nil;
                                                      self.view.hidden = NO;
                                                  }
                                              }];
                         }];
        
    };
    
    [super dismissViewControllerAnimated:animated completion:^{
        CALayer *layer = primaryView.layer;
        layer.zPosition = 0;
    }];
    
    primaryView.transform =  CGAffineTransformScale(primaryView.transform, kViewScaling, kViewScaling);

    dispatch_time_t modalDelay =
    dispatch_time(DISPATCH_TIME_NOW, 20000000);
    dispatch_after(modalDelay, dispatch_get_main_queue(), animationBlock);
}

// override the push method
- (void)pushViewController:(UIViewController *)viewController animated:(BOOL)animated {    
    [self.screenShotsList addObject:[self capture]];
    
    if (_isMoving) {
        [self moveEndWithAnimated:NO];
    }
    
    [super pushViewController:viewController animated:animated];
}

// override the pop method
- (UIViewController *)popViewControllerAnimated:(BOOL)animated {
    [self.screenShotsList removeLastObject];
    
    if (_isMoving) {
        [self moveEndWithAnimated:NO];
    }
    
    return [super popViewControllerAnimated:animated];
}

- (NSArray *)popToViewController:(UIViewController *)viewController animated:(BOOL)animated {
    NSInteger index = [self.viewControllers indexOfObject:viewController];
    NSIndexSet *indexs = [NSIndexSet indexSetWithIndexesInRange:NSMakeRange(index + 1, self.screenShotsList.count - index - 1)];
    
    [self.screenShotsList removeObjectsAtIndexes:indexs];
    
    if (_isMoving) {
        [self moveEnd];
        animated = NO;
    }
    return [super popToViewController:viewController animated:animated];
}

- (NSArray *)popToRootViewControllerAnimated:(BOOL)animated {
    [self.screenShotsList removeAllObjects];
    
    if (_isMoving) {
        [self moveEnd];
        animated = NO;
    }
    
    return [super popToRootViewControllerAnimated:animated];
}

- (void)setCanDragBackInMainView:(BOOL)canDragBackInMainView {
    _canDragBackInMainView = canDragBackInMainView;
    
    [self.view removeGestureRecognizer:_recognizer];
    [self.navigationBar removeGestureRecognizer:_recognizer];
    
    _recognizer = [[UIPanGestureRecognizer alloc] initWithTarget:self
                                                          action:@selector(paningGestureReceive:)];
    _recognizer.delegate = self;
    [_recognizer setMaximumNumberOfTouches:1];
    
    if (canDragBackInMainView) {
        [self.view addGestureRecognizer:_recognizer];
    } else {
        [self.navigationBar addGestureRecognizer:_recognizer];
    }
}

- (BOOL)canDragBackInMainView {
    return _canDragBackInMainView;
}

#pragma mark - Utility Methods -
- (UIImage *)capture {
    CGContextRef context = UIGraphicsGetCurrentContext();
    UIGraphicsBeginImageContextWithOptions(self.view.bounds.size, self.view.opaque, 0.0);
    [self.view drawViewHierarchyInRect:CGRectMake(0, 0, self.view.width, self.view.height) afterScreenUpdates:NO];
    
    UIImage * img = UIGraphicsGetImageFromCurrentImageContext();
    if(img == nil){
        CGContextSetFillColorWithColor(context, [UIColor clearColor].CGColor);
        CGContextFillRect(context, self.view.bounds);
        img = UIGraphicsGetImageFromCurrentImageContext();
    }
    UIGraphicsEndImageContext();
    return img;
}

// set lastScreenShotView 's position and alpha when paning
- (void)moveViewWithX:(float)x {
    x = x>kScreenWidth?kScreenWidth:x;
    x = x<0?0:x;
    
    CGRect frame = self.view.frame;
    frame.origin.x = x;
    self.view.frame = frame;
    
    float scale = (x/(kScreenWidth*20))+0.95;
    float alpha = 0.4 - (x/800);
    
    lastScreenShotView.transform = CGAffineTransformMakeScale(scale, scale);
    blackMask.alpha = alpha;
}

#pragma mark - Gesture Recognizer -

- (void)paningGestureReceive:(UIPanGestureRecognizer *)recoginzer {
    // If the viewControllers has only one vc or disable the interaction, then return.
    if (self.viewControllers.count < 2 || !self.canDragBack) return;
    
    // we get the touch position by the window's coordinate
    CGPoint touchPoint = [recoginzer locationInView:KEY_WINDOW];
    
    // begin paning, show the backgroundView(last screenshot),if not exist, create it.
    if (recoginzer.state == UIGestureRecognizerStateBegan) {
        
        _isMoving = YES;
        startTouch = touchPoint;
        
        if (!self.backgroundView) {
            CGRect frame = self.view.frame;
            
            self.backgroundView = [[UIView alloc]initWithFrame:CGRectMake(0, 0, frame.size.width , frame.size.height)];
            [self.view.superview insertSubview:self.backgroundView belowSubview:self.view];
            
            blackMask = [[UIView alloc]initWithFrame:CGRectMake(0, 0, frame.size.width , frame.size.height)];
            blackMask.backgroundColor = [UIColor blackColor];
            [self.backgroundView addSubview:blackMask];
        }

        self.backgroundView.hidden = NO;
        
        if (lastScreenShotView) [lastScreenShotView removeFromSuperview];
        
        UIImage *lastScreenShot = [self.screenShotsList lastObject];
        lastScreenShotView = [[UIImageView alloc]initWithImage:lastScreenShot];
        [self.backgroundView insertSubview:lastScreenShotView belowSubview:blackMask];
        
        //End paning, always check that if it should move right or move left automatically
    } else if (recoginzer.state == UIGestureRecognizerStateEnded){
        
        if (touchPoint.x - startTouch.x > 50) {
            [UIView animateWithDuration:0.3 animations:^{
                [self moveViewWithX:kScreenWidth];
            } completion:^(BOOL finished) {
                
                _isMoving = NO;
                [self popViewControllerAnimated:NO];
                CGRect frame = self.view.frame;
                frame.origin.x = 0;
                self.view.frame = frame;
                self.backgroundView.hidden = YES;
            }];
        } else {
            [UIView animateWithDuration:0.3 animations:^{
                [self moveViewWithX:0];
            } completion:^(BOOL finished) {
                _isMoving = NO;
                self.backgroundView.hidden = YES;
            }];
            
        }
        return;
        // cancal panning, alway move to left side automatically
    } else if (recoginzer.state == UIGestureRecognizerStateCancelled){
        
        [self moveEnd];

        return;
    }
    
    // it keeps move with touch
    if (_isMoving) {
        [self moveViewWithX:touchPoint.x - startTouch.x];
    }
}

- (void)moveEndWithAnimated:(BOOL)animate {
    if (animate) {
        [UIView animateWithDuration:0.3 animations:^{
            [self moveViewWithX:0];
        } completion:^(BOOL finished) {
            _isMoving = NO;
            self.backgroundView.hidden = YES;
        }];
    } else {
        [self moveViewWithX:0];
        _isMoving = NO;
        self.backgroundView.hidden = YES;
    }
}

- (void)moveEnd {
    [self moveEndWithAnimated:YES];
}

- (BOOL)gestureRecognizerShouldBegin:(UIGestureRecognizer *)gestureRecognizer {
    BOOL ret = NO;
    if (gestureRecognizer == _recognizer) {
        CGPoint touchPoint = [gestureRecognizer locationInView:KEY_WINDOW];
        if (touchPoint.x < (kScreenWidth / 2 - 50)) {
            ret = YES;
        }
    }
    return ret;
}

@end
